package beautiful.butterfly.server.httpserver.handler;

import beautiful.butterfly.server.application.Application;
import beautiful.butterfly.server.httpserver.mvc.Constant;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpContentCompressor;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.HttpServerExpectContinueHandler;
import io.netty.handler.codec.http.cors.CorsConfig;
import io.netty.handler.codec.http.cors.CorsConfigBuilder;
import io.netty.handler.codec.http.cors.CorsHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.stream.ChunkedWriteHandler;

public class HttpServiceChannelInitializer extends ChannelInitializer<SocketChannel> {

    private final SslContext sslContext;
    private final Application application;
    private final boolean enableGzip;
    private final boolean enableCors;
    private HttpServer httpServer;

    public HttpServiceChannelInitializer(SslContext sslContext, Application application, HttpServer httpServer) {
        this.sslContext = sslContext;
        this.application = application;
        this.httpServer = httpServer;

        this.enableGzip = application.environment().getBoolean(Constant.ENV_KEY_GZIP_ENABLE, false);
        this.enableCors = application.environment().getBoolean(Constant.ENV_KEY_CORS_ENABLE, false);
    }

    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline channelPipeline = socketChannel.pipeline();
        if (sslContext != null) {
            channelPipeline.addLast(sslContext.newHandler(socketChannel.alloc()));
        }
        if (enableGzip) {
            channelPipeline.addLast(new HttpContentCompressor());
        }
        channelPipeline.addLast(new HttpServerCodec(36192 * 2, 36192 * 8, 36192 * 16, false));
        channelPipeline.addLast(new HttpServerExpectContinueHandler());
        channelPipeline.addLast(new HttpObjectAggregator(Integer.MAX_VALUE));
        channelPipeline.addLast(new ChunkedWriteHandler());
        if (enableCors) {
            CorsConfig corsConfig = CorsConfigBuilder.forAnyOrigin().allowNullOrigin().allowCredentials().build();
            channelPipeline.addLast(new CorsHandler(corsConfig));
        }

        channelPipeline.addLast(new HttpServiceChannelInboundHandler(application, this.httpServer));
    }
}
